﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace DataAccess
{
    public class DBHelper
    {
        /// <summary>
        /// コネクション名
        /// </summary>
        protected static string ProviderName = ConfigurationManager.ConnectionStrings["dbConnection"].ProviderName;

        /// <summary>
        /// プロバイダー文字列
        /// </summary>
        /// <remarks>Create by You</remarks>
        protected static string ConnectionString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;

        /// <summary>
        /// 指定したプロバイダー名の DbProviderFactory のインスタンス。
        /// </summary>
        /// <remarks>Create by You</remarks>
        protected static DbProviderFactory DbFactory = DbProviderFactories.GetFactory(ProviderName);
        
        public DBHelper()
        {

        }

        /// <summary>
        /// SQLコマンドを準備する。
        /// </summary>
        /// <param name="command">コマンド</param>
        /// <param name="trans">パラメータ</param>
        /// <param name="commandText">コマンド テキスト</param>
        /// <param name="commandType">コマンドタイプ</param>
        /// <param name="parmList">コマンド パラメータ</param>
        /// <remarks>Create by You</remarks>
        private static void prepareCommand(DbCommand command,
                                           DbTransaction trans,
                                           string commandText,
                                           CommandType commandType,
                                           IList<DbParameter> parmList)
        {
            //コマンドを設定する
            command.CommandText = commandText;
            command.CommandType = commandType;

            //データベーストランザクションが存在するの場合、トランザクションをコマンドに設定する
            if (trans != null)
            {
                command.Transaction = trans;
            }
            if (parmList != null)
            {
                foreach (DbParameter param in parmList)
                {
                    command.Parameters.Add(param);
                }
            }
        }
        
        /// <summary>
        /// パラメータの作成
        /// </summary>
        /// <param name="connector"></param>
        /// <param name="paramName"></param>
        /// <param name="paramValue"></param>
        /// <returns></returns>
        /// <remarks>
        /// 必要に応じて、Direction,DbTypeの引数も追加する
        /// </remarks>
        public static DbParameter createParam(IDbConnector connector,
                                             string paramName,
                                             object paramValue)
        {
            DbParameter param = connector.factory().CreateParameter();
            param.ParameterName = paramName;
            param.Value = paramValue;
            return param;
        }

        /// <summary>
        /// クエリを実行し、そのクエリが返す結果セットの最初の行にある最初の列を返します。
        /// </summary>
        /// <param name="connector">DB接続管理クラス</param>
        /// <param name="sql">SQL文字列</param>
        /// <param name="parmList">コマンド パラメータ</param>
        /// <returns>結果セットの最初の行の最初の列。結果セットが空の場合は、Nothing参照。</returns>
        /// <remarks>Create by You</remarks>

        public static object getSingle(IDbConnector connector ,
                                     string sql ,
                                     IList<DbParameter> parmList)
        {
            //クエリの返す結果
            Object singleValue;
            using (DbCommand command = connector.connection().CreateCommand())
            {
                DBHelper.prepareCommand(command, connector.transaction(), sql, System.Data.CommandType.Text, parmList);
                singleValue = command.ExecuteScalar();
                command.Parameters.Clear();
            }
                
            return singleValue;
        }

        /// <summary>
        /// 検索SQLを実行する(実行結果のレコードセットをパラメータdtに作成する)。
        /// </summary>
        /// <param name="connector">DB接続インタフェース</param>
        /// <param name="sql">SQL文字列</param>
        /// <param name="dt">データテーブル</param>
        /// <param name="parmList">コマンド パラメータ</param>
        /// <remarks></remarks>
        public static void query(IDbConnector connector,
                            string sql,
                            DataTable dt,
                            IList<DbParameter> parmList)
        {
            //Dim conn DbConnection = connector.GetConnector()
            using (DbCommand command = connector.connection().CreateCommand()) {
                prepareCommand(command, connector.transaction(), sql, System.Data.CommandType.Text, parmList);
                using (DbDataAdapter adapter = connector.factory().CreateDataAdapter())
                {
                    adapter.SelectCommand = command;
                    adapter.Fill(dt);
                }
                command.Parameters.Clear();
            }
        }


        /// <summary>
        /// 検索SQLを実行する。
        /// </summary>
        /// <param name="sql">SQL文字列</param>
        /// <param name="parmList">SQLパラメータ</param>
        /// <returns>データセット</returns>
        /// <remarks>Create by You</remarks>
        public static DataSet query(IDbConnector connector,
                                string sql,
                                IList<DbParameter> parmList = null,
                                Boolean isPaging = false)
        {

            DataSet ds = new DataSet();

            //コネクションに関連付けられているデータベースコマンドオブジェクトを作成する
            using (DbCommand command = connector.connection().CreateCommand())
            {
                //すべてのステップをコマンド ライン コマンドを実行する準備をするようにします
                prepareCommand(command, connector.transaction(), sql, System.Data.CommandType.Text, parmList);

                //データベースファクトリオブジェクトを作成する
                using (DbDataAdapter adapter = connector.factory().CreateDataAdapter())
                {
                    adapter.SelectCommand = command;
                    adapter.Fill(ds);
                }
                
                command.Parameters.Clear();
            }
            
            //SQLで指定した範囲検索の場合、ページングフラグを削除する
            if (isPaging) {
                ds.Tables[0].Columns.Remove("rn_");
            }
            
            return ds;
        }


        /// <summary>
        /// 更新、削除、挿入SQLを実行します
        /// </summary>
        /// <param name="sql">SQL文字列</param>
        /// <param name="connector">コネクション</param>
        /// <param name="commanType">コマンドタイプ</param>
        /// <param name="parmList">コマンド パラメータ</param>
        /// <returns>実行件数</returns>
        /// <remarks>Create by You</remarks>

        public static int executeSql(IDbConnector connector ,
                                      string sql ,
                                      IList<DbParameter> parmList ,
                                      CommandType commanType  = CommandType.Text)
        {
            //実行件数
            int rows = 0;

            //コネクションに関連付けられているデータベースコマンドオブジェクトを作成する
            using (DbCommand command = connector.connection().CreateCommand()) {
                //すべてのステップをコマンド ライン コマンドを実行する準備をするようにします
                prepareCommand(command, connector.transaction(), sql, commanType, parmList);
                //ステートメントを実行し、影響を受けた行数を返します
                rows = command.ExecuteNonQuery();
                command.Parameters.Clear();
            }
            //実行件数を戻り
            return rows;
        }

        /// <summary>
        /// データベースクラスを実装する。
        /// </summary>
        /// <param name="paramName">パラメータ名</param>
        /// <param name="paramValue">パラメータ値</param>
        /// <returns>データベースパラメータ</returns>
        /// <remarks>Create by You</remarks>
        public static DbParameter createDbParameter(string paramName,
                                                    object paramValue)
        {

            //データベースパラメータを作成する
            DbParameter param  = DbFactory.CreateParameter();
            param.ParameterName = paramName;
            param.Value = paramValue;
            return param;
        }

        /// <summary>
        /// データベースクラスを実装する。
        /// </summary>
        /// <param name="paramName">パラメータ名</param>
        /// <param name="paramValue">パラメータ値</param>
        /// <param name="paramType">パラメータタイプ</param>
        /// <returns>データベースパラメータ</returns>
        /// <remarks>Create by You</remarks>
        public static DbParameter createDbParameter(string paramName,
                                                 object paramValue,
                                                 DbType paramType)
        {
            //データベースパラメータを作成する
            DbParameter param = DbFactory.CreateParameter();
            param.ParameterName = paramName;
            param.Value = paramValue;
            param.DbType = paramType;
            return param;
        }

        /// <summary>
        /// 特殊文字列の置換え
        /// </summary>
        /// <param name="inputStr">置換前の文字列</param>
        /// <returns>置換後の文字列</returns>
        /// <remarks></remarks>
        public static string escape(string inputStr)
        {
            string pattern = "(%|_|#)";
            string replacement = "#$1";
            return System.Text.RegularExpressions.Regex.Replace(inputStr, pattern, replacement);
        }
    }
}
